﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Printing;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Threading;
using FPPrinter.Models;
using FPPrinter.Models.Doc;
using FPPrinter.Models.Printers;
using FPPrinter.Models.SourceFiles;
using FPPrinter.utiles;
using Prism.Commands;
using Prism.Mvvm;

namespace FPPrinter
{
    public class SysVM : BindableBase
    {
        private Sys _sys;

        public DelegateCommand PrintAll { get; set; }
        public DelegateCommand PrintSelectedDoc { get; set; }
        public DelegateCommand OptimizeCmd { get; set; }
        public DelegateCommand RemoveFile { get; set; }

        public DelegateCommand RemoveAllFiles { get; set; }

        // public DelegateCommand PrintAll { get; set; }
        // public DelegateCommand PrintAll { get; set; }
        public SysVM(Sys sys)
        {
            _sys = sys;


            _sys.SourceFileManager.FilesChanged += SourceFileManagerOnFilesChanged;
            _sys.OptimzedDocManager.DocsChanged += OptimzedDocManagerOnDocsChanged;

            Printers=new ObservableCollection<PrinterVm>(   
                _sys.PrinterManager.Printers.Select(x => new PrinterVm(x))
             );
            

            #region a

            //   
            var Document = new FixedDocument();
            var pc = new PageContent();

            var fixedPage1 = new FixedPage();
            fixedPage1.Children.Add(
                new Grid()
                {
                    Background = Brushes.Aqua,
                    Height = 100,
                    Width = 200
                });

            pc.Child = fixedPage1;

            Document.Pages.Add(pc);

            this.SelectedFixedDoc = Document;

            #endregion


            PrintAll = new DelegateCommand(DoPrintAll, HasDocs);
            PrintSelectedDoc = new DelegateCommand(DoPrintSelectedDoc, () => SelectedDoc != null);

            RemoveFile = new DelegateCommand(DoRemoveFile, () => SelectedSourceFile != null);
            RemoveAllFiles = new DelegateCommand(DoRemoveAllFiles, HasFiles);
            OptimizeCmd = new DelegateCommand(DoOptimizeCmd, HasFiles);
        }

        void Notecmd()
        {
            PrintAll?.RaiseCanExecuteChanged();
            PrintSelectedDoc?.RaiseCanExecuteChanged();
            RemoveFile?.RaiseCanExecuteChanged();
            RemoveAllFiles?.RaiseCanExecuteChanged();
            OptimizeCmd?.RaiseCanExecuteChanged();
        }

        private bool HasFiles()
        {
            return SourceFiles.Count > 0;
        }

        private void DoOptimizeCmd()
        {
            Console.WriteLine("Optimize");
            _sys.OptimizeFiles();

            _documentViewer.FitToWidth();
        }


        private SourceFileVm _SelectedSourceFile;

        public SourceFileVm SelectedSourceFile
        {
            get => _SelectedSourceFile;
            set
            {
                _SelectedSourceFile = value;
                Notecmd();
            }
        }


        private void DoRemoveAllFiles()
        {
            // _sys.SourceFileManager.Clear();
            _sys.ClearAllFiles();
            SelectedDoc = null;
        }

        private void DoRemoveFile()
        {
            _sys.SourceFileManager.Remove(SelectedSourceFile.Url);
        }


        public string SelectedPrinterName
        {
            get=> _sys.SelectedPrinterName;
            set
            {
                _sys.SelectedPrinterName = value;
                value.Echo();
            }
        }

        #region Printers

        private ObservableCollection<PrinterVm> _printers;

        public ObservableCollection<PrinterVm> Printers
        {
            get { return _printers; }
            set
            {
                _printers = value;
                OnPropertyChanged(nameof(Printers));
            }
        }

        #endregion


 


        private void DoPrintSelectedDoc()
        {
            SelectedDoc.Doc.Print(SelectedPrinterName);
        }

        private bool HasDocs()
        {
            return OptimizedDocs.Count > 0;
        }

        private void DoPrintAll()
        {
            foreach (var d in OptimizedDocs)
            {
                d.Doc.Print(SelectedPrinterName);
            }
        }

        private void OptimzedDocManagerOnDocsChanged(object sender, IEnumerable<IOptimizedDoc> e)
        {
            1.UseUIThread(() =>
            {
                "opt changed".Echo();
                OptimizedDocs.Clear();
                OptimizedDocs.AddRange(
                    new ObservableCollection<OptimzedDocVm>(
                        e.Select(x => new OptimzedDocVm(x))
                    ));

                Notecmd();
            });
        }

        private void SourceFileManagerOnFilesChanged(object sender, IEnumerable<ISourceFile> e)
        {
            1.UseUIThread(() =>
            {
                SourceFiles.Clear();
                foreach (var f in e)
                {
                    SourceFiles.Add(new SourceFileVm(f));
                }

                OnPropertyChanged(nameof(ShowData));
                OnPropertyChanged(nameof(ShowHelpText));
                Notecmd();


            });


            Task.Run(() =>
            {
                try
                {
                    if (_isruning ) return;
                    _isruning = true;
                    Thread.Sleep(1500);
                    1.UseUIThread(()=> DoOptimizeCmd());  
                }
                finally
                {
                    _isruning = false;

                }
                    
            });
            
            // 1.Debounce<object>((a) =>
            // {
            //     // 1.UseUIThread(() => DoOptimizeCmd());
            //      DoOptimizeCmd() ;
            //      
            // }, 600 );
        }

        private bool _isruning = false;

        public ObservableCollection<SourceFileVm> SourceFiles { get; set; } = new ObservableCollection<SourceFileVm>();

        public void LoadFiles(IEnumerable<string> pdfFiles)
        {
            
            //call
            _sys.SourceFileManager.Analysis(pdfFiles.ToArray());
        }

        public bool ShowHelpText { get=>!ShowData;  }  
        public bool ShowData { get=> SourceFiles.Count>0;   } 


        public ObservableCollection<OptimzedDocVm> OptimizedDocs { get; set; } =
            new ObservableCollection<OptimzedDocVm>();

        private OptimzedDocVm _selectedDoc;

        public OptimzedDocVm SelectedDoc
        {
            get => _selectedDoc;
            set
            {
                _selectedDoc = value;
                try
                {
                    if (_selectedDoc!=null )
                        _documentViewer.Document = _selectedDoc.FixedDocument;
                    else
                    {
                        _documentViewer.Document = null;
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    
                }
                Notecmd();
            }
        }

        public FixedDocument SelectedFixedDoc { get; set; }


        public void OptimizeFiles()
        {
            _sys.OptimizeFiles();
        }


        private DocumentViewer _documentViewer;

        public void Register(DocumentViewer ver)
        {
            _documentViewer = ver;
        }


        public void Print()
        {
            _sys.PrinterManager.ScanForPrinter();
            _selectedDoc.Doc.Print("Note");
        }
    }

    public class PrinterVm: BindableBase
    {
        private IPrinter _printer;
        public PrinterVm(  IPrinter printer)
        {
    
            _printer = printer;
            
            Name = _printer.Name ;
            DoubleSided = _printer.DoubleSided ;
        }

        public override string ToString()
        {
            return Name ;
        }

        public String Name { get; set; }
        public bool DoubleSided { get; set; }
        public String DoubleSidedText { get=> !DoubleSided?"单":"双";   }
        
        
    }

    public class OptimzedDocVm : BindableBase
    {
        IOptimizedDoc _doc;

        public FixedDocument FixedDocument
        {
            get => _doc?.FixedDocWpf;
        }

        public OptimzedDocVm(IOptimizedDoc optimizedDoc)
        {
            _doc = optimizedDoc;

            if (_doc is ShortOptimizedDoc)
                Name = $"合并短发票，共{_doc.Pages.Count()}页";
            else
                Name = $"长发票，共{_doc.Pages.Count()}页";
        }

        public string Name { get; set; }

        public IOptimizedDoc Doc
        {
            get => _doc;
        }
    }
}